package com.shareware.common.rxBus

import android.annotation.SuppressLint
import com.shareware.common.annotation.Subscribe
import io.reactivex.Observable
import io.reactivex.Scheduler
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import io.reactivex.subjects.Subject
import java.lang.reflect.Method
import java.util.*

/**
 * desc: 功能描述
 * email: mobiledeveloper@qq.com
 */
object RxBus {
    //发布者
    private val bus: Subject<Any> = PublishSubject.create<Any>().toSerialized()

    //存放订阅者信息
    private val subscriptions = HashMap<Any, CompositeDisposable>()

    /**
     * 发布事件
     *
     * @param code code
     * @param obj  为需要被处理的事件
     */
    fun send(code: Int, obj: Any) {
        bus.onNext(Message(code, obj))
    }

    /**
     * 订阅者注册
     *
     * @param subscriber Object
     */
    @SuppressLint("CheckResult")
    fun register(subscriber: Any) {
        Observable.just(subscriber).filter { subscriptions[it] == null }
            .flatMap { Observable.fromArray(*it.javaClass.declaredMethods) }
            .map {
                it.isAccessible = true
                it
            }.filter { it.isAnnotationPresent(Subscribe::class.java) }
            .subscribe { addSubscription(it, subscriber) }
    }

    /**
     * 解除订阅者
     *
     * @param subscriber 订阅者
     */
    fun unRegister(subscriber: Any?) {
        subscriptions.remove(subscriber ?: return)?.dispose()
    }

    /**
     * 添加订阅
     *
     * @param m          方法
     * @param subscriber 订阅者
     */
    private fun addSubscription(m: Method, subscriber: Any) {
        //获取方法内参数
        val parameterType = m.parameterTypes
        //只获取第一个方法参数，否则默认为Object
        var cla: Class<*> = Any::class.java
        if (parameterType.isNotEmpty()) {
            cla = parameterType[0]
        }
        //获取注解
        val sub = m.getAnnotation(Subscribe::class.java)
        //订阅事件
        val disposable = tObservable(sub!!.tag, cla)
            .observeOn(getScheduler(sub.thread))
            .subscribe({
                try {
                    if (parameterType.isEmpty()) {
                        m.invoke(subscriber)
                    } else {
                        m.invoke(subscriber, it)
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }, { println("this object is not invoke") })
        val subs: CompositeDisposable = subscriptions[subscriber] ?: CompositeDisposable()
        subs.add(disposable)
        subscriptions[subscriber] = subs
    }

    /**
     * 订阅事件
     */
    private fun tObservable(code: Int, eventType: Class<*>): Observable<*> {
        return bus.ofType(Message::class.java)//判断接收事件类型
            .filter { it.code == code }
            .map { (_, any) -> any }.cast(eventType)
    }

    /**
     * 获取Scheduler
     */
    private fun getScheduler(threadMode: ThreadMode): Scheduler {
        return when (threadMode) {
            ThreadMode.NEW_THREAD -> Schedulers.newThread()
            ThreadMode.IO -> Schedulers.io()
            ThreadMode.COMPUTATION -> Schedulers.computation()
            ThreadMode.TRAMPOLINE -> Schedulers.trampoline()
            else -> AndroidSchedulers.mainThread()
        }
    }
}
//另一种写法
//inline fun <reified T> LifecycleOwner.observeEvent(
//    vararg tags: String = arrayOf(),
//    scheduler: Scheduler = Schedulers.trampoline(),
//    lifecycleEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY,
//    noinline block: Bus<T>.() -> Unit
//) {
//
//    val disposable =
//        _bus.filter { val tag = it.tag; it.event is T && (tags.isEmpty() && tag.isBlank() || tags.contains(tag)) }
//            .map {
//                @Suppress("UNCHECKED_CAST")
//                it as Bus<T>
//            }
//            .observeOn(scheduler).onTerminateDetach().subscribe(block)
//
//    lifecycle.addObserver(object : LifecycleEventObserver {
//        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
//            if (lifecycleEvent == event) {
//                disposable.dispose()
//            }
//        }
//    })
//}
//
//fun LifecycleOwner.observeTag(
//    vararg tags: String,
//    scheduler: Scheduler = Schedulers.trampoline(),
//    lifecycleEvent: Lifecycle.Event = Lifecycle.Event.ON_DESTROY,
//    block: String.() -> Unit
//) {
//
//    val disposable = _bus
//        .filter { it.event.javaClass == TagEvent::class.java && tags.contains(it.tag) }
//        .map { it.tag }
//        .observeOn(scheduler)
//        .onTerminateDetach()
//        .subscribe(block)
//
//    lifecycle.addObserver(object : LifecycleEventObserver {
//        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
//            if (lifecycleEvent == event) {
//                disposable.dispose()
//            }
//        }
//    })
//}
//
//inline fun <reified T> receiveEvent(
//    vararg tags: String = arrayOf(),
//    scheduler: Scheduler = Schedulers.trampoline(),
//    noinline block: Bus<T>.() -> Unit
//): Disposable {
//    return _bus.filter {
//        val tag = it.tag
//        it.event is T && (tags.isEmpty() && tag.isBlank() || tags.contains(tag))
//    }.map {
//        @Suppress("UNCHECKED_CAST")
//        it as Bus<T>
//    }.observeOn(scheduler).onTerminateDetach().subscribe(block)
//}
//
//fun receiveTag(
//    vararg tags: String,
//    scheduler: Scheduler = Schedulers.trampoline(),
//    block: String.() -> Unit
//): Disposable {
//    return _bus.filter { it.event.javaClass == TagEvent::class.java && tags.contains(it.tag) }
//        .map { it.tag }
//        .observeOn(scheduler)
//        .onTerminateDetach()
//        .subscribe(block)
//}